﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace GDF_kaart_inlezen
{
    public abstract class ReadingStrategy : Strategy
    {
        public String recordCode; //Stores the code belonging to the record
        protected int counter; //holds the starting index that the current substring has in the original record

        /// <summary>
        /// This method gives the value that is stored in the field that is referenced by fieldName. It also adjusts the recordString, so it now starts at the next field and the counter, so it holds the right index
        /// </summary>
        /// <param name="fieldName">Name of the field to read out</param>
        /// <param name="recordString">The string which contains the part of the record still to read, with the field to which fieldName refers at index 0 in the string</param>
        /// <returns>The value that the field with name=fieldName holds</returns>
        protected String GetFieldValue(string fieldName, ref string recordString)
        {
            int fieldSize = FieldSizeStatic.GetFieldSize(fieldName);
            recordString = AdjustString(recordString, fieldSize);
            String fieldValue = recordString.Substring(0, fieldSize);
            recordString = recordString.Substring(fieldSize);
            counter = counter + fieldSize;
            return fieldValue.Trim();
        }

        /// <summary>
        /// This method adjusts the recordString if needed according to the original GDF lines
        /// </summary>
        /// <param name="recordString">The string which contains the part of the record still to read</param>
        /// <param name="nextFieldSize">Size of the next field to read out</param>
        /// <returns>The recordString, now starting at the next field</returns>
        protected String AdjustString(string recordString, int nextFieldSize)
        {
            int charsLeftInLine = 77 - (counter % 77); //The number of character still left in the original GDF line
            if (charsLeftInLine < nextFieldSize)
            {
                counter = counter + charsLeftInLine;
                return recordString.Substring(charsLeftInLine);
            }
            else return recordString;
        }

        /// <summary>
        /// This method processes a record of the recordCode type
        /// </summary>
        /// <param name="record">The complete record to process (including the code)</param>
        public abstract void Process(string record);
    }

    public static class FieldSizeStatic
    {
        //Please organize alphabetically when adding new KeyValuePairs to make sure we have no double entries
        //Please do not add fields that have infinite length. These fields always end the record.
        static Dictionary<String, int> _dict = new Dictionary<String, int> //This Dictionary holds all the fieldNames, with their respectable fieldSizes, that the GDF format uses
        {
            {"ABS_REL", 1},
            {"ALBUM_ID", 10},
            {"AREA_ID", 10},
            {"ATT_COMP", 2},
            {"ATT_COR", 2},
            {"ATT_DIR", 1},
            {"ATT_TYPE", 2},
            {"ATT_VAL", 10},
            {"CHAR_SET", 10},
            {"CNT_CODE", 3},
            {"COMF_ID", 10},
            {"CONT_VOL", 1},
            {"CORI_DATA", 6},
            {"CREA_DATA", 6},
            {"DASET_ID", 10},
            {"DAT_NAME", 47},
            {"DATA_TYPE", 2},
            {"DATA_UNIT", 3},
            {"DATEL_ID", 5},
            {"DATT_VAL", 10},
            {"DEC_DATE", 6},
            {"DEC_VALUE", 5},
            {"DESC_ID", 5},
            {"DEV_ANNUAL", 5},
            {"ED_DATE", 8},
            {"EDGE_ID", 10},
            {"EXT_ID", 10},
            {"EL_CODE", 4},
            {"FACE_ID", 10},
            {"FEAT_ID", 10},
            {"FEAT_CAT", 2},
            {"FEAT_CODE", 4},
            {"FEAT_COMP", 2},
            {"FEAT_NAME", 20},
            {"FEAT_SYN", 20},
            {"FIELD_SIZE", 2},
            {"FKNOT_ID", 10},
            {"FROM", 5},
            {"FROM_ID", 10},
            {"G_TYPE", 1},
            {"HMAG_INT", 5},
            {"IDSI_NR", 13},
            {"INT_ID", 10},
            {"KNOT_ID", 10},
            {"LAN_CODE", 3},
            {"LAY_ID", 2},
            {"LFACE_ID", 10},
            {"LINE_ID", 10},
            {"MAGN_ID", 5},
            {"MANDATRY", 1},
            {"MAX_AGE", 6},
            {"MAX_VAL", 12},
            {"MIN_VAL", 12},
            {"NAME_ID", 10},
            {"NO_DATA", 6},
            {"NUM_ATT", 5},
            {"NUM_CNTRY", 2},
            {"NUM_COORD", 5},
            {"NUM_DASET", 2},
            {"NUM_EDGE", 10},
            {"NUM_FACE", 10},
            {"NUM_FEAT", 2},
            {"NUM_KNOT", 5},
            {"NUM_LAN", 2},
            {"NUM_NAME", 2},
            {"NUM_PARTS", 10},
            {"NUM_THEM", 2},
            {"ORIENT", 2},
            {"POINT_ID", 10},
            {"POS_NEG", 2},
            {"Q_PLAN", 2},
            {"REC_CODE", 2},
            {"REC_DESCR", 2},
            {"REF_LAT", 10},
            {"REF_LONG", 10},
            {"REL_ACC", 2},
            {"REL_CODE", 4},
            {"REL_ID", 10},
            {"REL_NAME", 40},
            {"REPEAT", 1},
            {"RFACE_ID", 10},
            {"ROT_Z", 5},
            {"SATT_ID", 10},
            {"SCALE_FAC", 5},
            {"SECT_ID", 10},
            {"SEM_MAJOR", 8},
            {"SEMI_MINOR", 8},
            {"SPLIT_IND", 1},
            {"STAN_NAME", 10},
            {"STATUS", 2},
            {"SUP_NAME", 20},
            {"SURV_DATE", 6},
            {"THEM_COD", 2},
            {"TIME_ID", 10},
            {"TKNOT_ID", 2},
            {"TO", 5},
            {"TOT_VOL", 4},
            {"TRANS_X", 5},
            {"TRANS_Y", 5},
            {"TRANS_Z", 5},
            {"UNIT_EXP", 2},
            {"VERSION", 4},
            {"VMAG_INT", 5},
            {"VOL_ID", 4},
            {"VOL_SIZE", 10},
            {"VOLENDTEXT", 76},
            {"X_COORD", 11},
            {"X_MAX", 11},
            {"X_MIN", 11},
            {"X_OFFSET", 11},
            {"XY_ACC", 3},
            {"XY_CONFAC", 2},
            {"XY_RES", 3},
            {"XYZ_ID", 10},
            {"Y_COORD", 11},
            {"Y_MAX", 11},
            {"Y_MIN", 11},
            {"Y_OFFSET", 11},
            {"Z_ACC", 2},
            {"Z_CONFAC", 2},
            {"Z_COORD", 11},
            {"Z_OFFSET", 11}
        };

        /// <summary>
        /// Gets the fieldSize for the given field with name=fieldName
        /// </summary>
        /// <param name="fieldName">The name of the field</param>
        /// <returns>The number of characters this field holds</returns>
        public static int GetFieldSize(string fieldName)
        {
            int result;
            if (_dict.TryGetValue(fieldName, out result))
            {
                return result;
            }
            else
            {
                throw new KeyNotFoundException("The called fieldname (" + fieldName + ") is not included in the dictionary");
            }
        }
    }
}